#pragma once
#include <mutex>
#include <memory>
#include <condition_variable>
#include <functional>
#include <thread>
#include <atomic>
#include "buffer.hpp"

namespace log
{
    using func = std::function<void(Buffer &)>;
    // 决定存储空间满时是扩容还是阻塞
    enum AsyncType
    {
        ASYNC_SAFE,  // 阻塞
        ASYNC_UNSAFE // 扩容
    };

    class AsyncLooper
    {
    public:
        using ptr = std::shared_ptr<AsyncLooper>;
        AsyncLooper(const func &cb, AsyncType type = ASYNC_SAFE)
            : _type(type), _callBack(cb), _stop(false), _thread(std::thread(&AsyncLooper::threadEntry, this)) {}
        ~AsyncLooper() { stop(); }
        void stop()
        {
            _stop = true;
            _cond_con.notify_all(); // 唤醒所有的工作线程
            _thread.join();
        }
        void push(const char *data, int len)
        {
            std::unique_lock<std::mutex> lock(_mutex); // 上锁
            //当_type的类型是ASYNC_SAFE时才进行阻塞
            if (_type == ASYNC_SAFE)
            {
                _cond_pro.wait(lock, [&]()
                               { return _pro_buffer.writeAbleLen() >= len; }); // 判断可写空间是否大于等于len,否则就阻塞线程
            }
            _pro_buffer.push(data, len);
            _cond_con.notify_one(); // 唤醒工作线程
        }

    private:
        // 线程入口函数
        void threadEntry()
        {
            while (1)
            {
                {
                    // 判断生产缓冲区是否有数据,如果有则交换,没有则阻塞
                    std::unique_lock<std::mutex> lock(_mutex);
                    //处理在生产缓冲区内还存在数据时,可能提前退出导致剩于的数据得不到处理的情况
                    if(_stop && _pro_buffer.empty())
                    {
                        break;
                    }
                    _cond_con.wait(lock, [&]()
                                   { return _stop || !_pro_buffer.empty(); });
                    _con_buffer.swap(_pro_buffer);
                    //当_type的类型是ASYNC_SAFE时才可能阻塞,也因此当_type的类型是ASYNC_SAFE时才需要唤醒
                    if(_type == ASYNC_SAFE)
                    {
                        _cond_pro.notify_all(); // 唤醒生产线程继续生产     
                    }
                }
                _callBack(_con_buffer); // 对消费缓冲区进行数据处理
                _con_buffer.reset();   // 初始化
            }
        }
    private:
        func _callBack; // 回调函数
        AsyncType _type;
        std::atomic<bool> _stop; // 工作器停止标志
        Buffer _pro_buffer;      // 生产缓冲区
        Buffer _con_buffer;      // 消费缓冲区
        std::mutex _mutex;
        // 条件变量
        std::condition_variable _cond_pro;
        std::condition_variable _cond_con;
        std::thread _thread; // 异步工作器的线程
    };
};